// tge.rs
// copyright zipxing@hotmail.com 2022~2023

//! objpool实现了一个简单的对象池
//! 核心功能是对象的重复利用，减少创建对象的开销
//! 也提供了create_sprites, draw_objs方法用于
//! 创建渲染精灵和绘制渲染对象

use crate::util::Point;
use log::info;
use std::collections::HashMap;

/// 游戏对象接口，需要实现new和reset方法
pub trait GObj {
    fn new(t: u8, ps: &Vec<Point>) -> Self;
    fn reset(&mut self, t: u8, ps: &Vec<Point>);
}

/// 游戏对象，id是对象池vector的偏移量索引
/// 用于唯一标识和访问对象
/// active标识对象是否活跃，回收对象时只需要
/// 把active设置成false
pub struct GameObject<T>
where
    T: GObj,
{
    pub id: usize,
    pub obj: T,
    pub active: bool,
}

/// pool放置游戏对象
/// map用于维护sprite和gameobject之间的对应关系
/// key是gameobject的id，value是sprite的id
/// 详情参看draw_objs
#[derive(Default)]
pub struct GameObjPool<T>
where
    T: GObj,
{
    pub map: HashMap<usize, usize>,
    pub pool: Vec<GameObject<T>>,
}

impl<T> GameObjPool<T>
where
    T: GObj,
{
    pub fn create(&mut self, otype: u8, ps: &Vec<Point>) {
        let mut find = false;
        // 查找可用的对象
        for o in &mut self.pool {
            if !o.active {
                o.obj.reset(otype, ps);
                o.active = true;
                find = true;
                break;
            }
        }
        // 如果没有找到，新建并加入对象池
        if !find {
            let l = self.pool.len();
            info!("create id...{}", l);
            let bo = GObj::new(otype, ps);
            self.pool.push(GameObject {
                id: l,
                obj: bo,
                active: true,
            });
        }
    }

    // 对活跃对象调用自定义闭包进行处理
    pub fn update_active<F>(&mut self, mut f: F) 
    where
        F: FnMut(&mut GameObject<T>),
    {
        for o in self.pool.iter_mut().filter(|o| o.active) {
            f(o);
        }
    }
}
